package com.song.rabbitmq.springbootorderrabbitmqproducerttl.ttl;


import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;


import java.util.HashMap;
import java.util.Map;

/**
 *
 * 设置队列TTL
 *      过期时间TTL表示可以对消息设置预期的时间，在这个时间内都可以被消费者接收获取；过了之后消息将自动被删除。
 *      RabbitMQ可以对消息和队列设置TTL。目前有两种方法可以设置。
 *          第一种方法是通过队列属性设置，队列中所有消息都有相同的过期时间。
 *          第二种方法是对消息进行单独设置，每条消息TTL可以不同。
 *      如果上述两种方法同时使用，则消息的过期时间以两者之间TTL较小的那个数值为准。
 *      消息在队列的生存时间一旦超过设置的TTL值，就称为dead message被投递到死信队列， 消费者将无法再收到该消息。
 *
 */

/*
    消息过期时间和队列过期时间在 RabbitMQ 中有以下区别：
        消息过期时间：消息过期时间是指在消息被发送到队列后，如果在指定的时间内没有被消费者消费，就会过期并被自动删除。可以通过设置消息的 expiration 属性来指定消息的过期时间。一旦消息过期，它将从队列中被移除，不再被消费者接收。
        队列过期时间：队列过期时间是指在队列中的消息的过期时间。可以通过设置队列的 x-expires 属性来指定队列的过期时间。一旦队列过期，队列及其中的所有消息都会被自动删除，无法再进行消费。

        总结来说，消息过期时间是针对单个消息的，在消息被发送到队列后，如果在指定的时间内没有被消费者消费，就会过期并从队列中移除。而队列过期时间是针对整个队列的，在队列上设置过期时间后，如果队列在指定的时间内没有被使用，整个队列及其中的所有消息都会被自动删除。
        需要注意的是，队列过期时间仅在队列不再被使用时触发，而消息过期时间是在消息被消费之前触发。因此，如果一个队列中的消息已经过期，但队列仍然处于活动状态，并且有消费者正在消费消息，那么过期的消息仍然可以被消费。
 */
public class Producer {
    public static void main(String[] args) {
        // 1: 创建连接工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();

        // 2: 设置连接属性
        connectionFactory.setHost("121.41.53.91");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/");
        connectionFactory.setUsername("admin");
        connectionFactory.setPassword("admin");

        Connection connection = null;
        Channel channel = null;
        try {
            // 3: 从连接工厂中获取连接
            connection = connectionFactory.newConnection("生产者");
            // 4: 从连接中获取通道channel
            channel = connection.createChannel();
            // 5: 申明队列queue存储消息
            /*
             *  如果队列不存在，则会创建
             *  Rabbitmq不允许创建两个相同的队列名称，否则会报错。
             *
             *  @params1： queue 队列的名称
             *  @params2： durable 队列是否持久化
             *  @params3： exclusive 是否排他，即是否私有的，如果为true,会对当前队列加锁，其他的通道不能访问，并且连接自动关闭
             *  @params4： autoDelete 是否自动删除，当最后一个消费者断开连接之后是否自动删除消息。
             *  @params5： arguments 可以设置队列附加参数，设置队列的有效期，消息的最大长度，队列的消息生命周期等等。
             * */
            Map<String,Object> args2 = new HashMap<>();
            args2.put("x-message-ttl",5000);
            channel.queueDeclare("ttl.queue", true, false, false, args2);
            // 6： 准备发送消息的内容
            String message = "你好，学相伴！！！";
            Map<String, Object> headers = new HashMap<String, Object>();
            headers.put("x", "1");
            headers.put("y", "1");
            AMQP.BasicProperties basicProperties = new AMQP.BasicProperties().builder()
                    .deliveryMode(2) // 传送方式
                    .priority(1)  // 优先级
                    .contentEncoding("UTF-8") // 编码方式
                    .expiration("3000") // 队列TTL过期时间，如果和消息TTL同时设置时候，以最小时间为准
                    .headers(headers).build(); //自定义属性
            // 7: 发送消息给中间件rabbitmq-server
            // @params1: 交换机exchange
            // @params2: 队列名称/routing
            // @params3: 属性配置
            // @params4: 发送消息的内容
            for (int i = 0; i <100 ; i++) {
                channel.basicPublish("", "ttl.queue", basicProperties, message.getBytes());
                System.out.println("消息发送成功!");
                Thread.sleep(1000);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            System.out.println("发送消息出现异常...");
        } finally {
            // 7: 释放连接关闭通道
            if (channel != null && channel.isOpen()) {
                try {
                    channel.close();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
            if (connection != null && connection.isOpen()) {
                try {
                    connection.close();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
    }
}
